package com.ynet.middleground.contract.model;

import java.time.LocalDateTime;
import java.util.List;

import org.dozer.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ynet.core.common.BaseReqObj;
import com.ynet.core.exception.BusinessException;
import com.ynet.middleground.contract.bean.*;
import com.ynet.middleground.contract.constant.SystemConsts;
import com.ynet.middleground.contract.dao.ContractTypeMapper;
import com.ynet.middleground.contract.dto.ContractTypeDTO;
import com.ynet.middleground.contract.entity.Contract;
import com.ynet.middleground.contract.entity.ContractType;
import com.ynet.middleground.contract.entity.Template;
import com.ynet.middleground.contract.utils.BeanUtil;

/**
 * @author liulx
 * @description 合约类型业务处理类
 * @date 2020-04-06 04:15
 */
@Component
public class ContractTypeModel extends ServiceImpl<ContractTypeMapper, ContractType> {

    @Autowired
    private Mapper mapper;

    @Autowired
    private TemplateModel templateModel;

    @Autowired
    UserCenterModel userCenterModel;

    /**
     * 查询合约类型列表
     *
     * @param req 基础请求类
     * @return 合约类型信息列表
     */
    public List<ContractTypeDTO> listContractType(BaseReqObj req) {
        LambdaQueryWrapper<ContractType> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractType::getChannel, req.getChannel());
        queryWrapper.eq(ContractType::getIsDeleted, SystemConsts.NOT_DELETED);
        if (req instanceof QueryContractTypeBaseReqObj && ((QueryContractTypeBaseReqObj)req).getFormatId() != null) {
            queryWrapper.eq(ContractType::getFormatId, ((FormatBaseReqObj)req).getFormatId());
        }
        List<ContractType> list = this.list(queryWrapper);
        return BeanUtil.mapList(mapper, list, ContractTypeDTO.class);
    }

    /**
     * 新增合约类型信息
     * 
     * @param req 新增合约类型请求类
     * @return 新增的合约类型 id
     */
    public Integer addContractType(AddContractTypeReq req) {
        // 校验是否重复
        checkRepeatContractType(req.getChannel(), req.getCode(), req.getName(), null);
        // 若上送业态 id，则查询业态是否有效
        if (null != req.getFormatId()) {
            userCenterModel.getFormatOrgInfo(req.getFormatId(), req);
        }
        ContractType contractType = mapper.map(req, ContractType.class);
        contractType.setChannel(req.getChannel());
        contractType.setCreateBy(req.getOperationUserId());
        contractType.setModifiedBy(req.getOperationUserId());
        contractType.setGmtCreate(LocalDateTime.now());
        contractType.setGmtModified(LocalDateTime.now());
        this.save(contractType);
        return contractType.getId();
    }

    /**
     * 更新合约类型信息
     * 
     * @param req 更新合约类型信息请求类
     */
    public void updateContractType(UpdateContractTypeReq req) {
        ContractType contractType = validContractType(req.getId(), req.getChannel());
        // 合约类型已关联业态，删除时却未上送业态，则不允许修改
        if (contractType.getFormatId() != null && req.getFormatId() == null) {
            throw new BusinessException("该合约类型已关联业态信息，请上送所属业态id！", "ECCT0009");
        }

        // 修改时上送的业态与关联业态的不一致，则不允许修改
        if (null != req.getFormatId() && !req.getFormatId().equals(contractType.getFormatId())) {
            throw new BusinessException("该合约类型关联业态信息与上送业态id不一致，请检查！", "ECCT0008");
        }
        // 校验该合约类型是否已被使用，已被使用的无法进行修改
        checkContractTypeIsUsed(contractType, req);
        // 校验是否重复
        checkRepeatContractType(req.getChannel(), req.getCode(), req.getName(), req.getId());
        mapper.map(req, contractType);
        contractType.setModifiedBy(req.getOperationUserId());
        contractType.setGmtModified(LocalDateTime.now());
        this.updateById(contractType);
    }

    /**
     * 删除合约类型信息
     * 
     * @param req 删除合约类型请求类
     */
    public void deleteContractType(DeleteContractTypeReq req) {
        ContractType contractType = validContractType(req.getId(), req.getChannel());

        // 合约类型已关联业态，删除时却未上送业态，则不允许删除
        if (contractType.getFormatId() != null && req.getFormatId() == null) {
            throw new BusinessException("该合约类型已关联业态信息，请上送所属业态id！", "ECCT0009");
        }
        // 删除时上送的业态与关联业态的不一致，则不允许删除
        if (null != req.getFormatId() && !req.getFormatId().equals(contractType.getFormatId())) {
            throw new BusinessException("该合约类型关联业态信息与上送业态id不一致，请检查！", "ECCT0008");
        }

        // 校验该合约类型是否已被使用，已被使用的无法进行删除
        checkContractTypeIsUsed(contractType, req);
        contractType.setIsDeleted(true);
        this.updateById(contractType);
    }

    /**
     * 根据渠道和合约类型代码、合约类型名称校验是否重复 <br />
     * 同一个渠道下，每个合约类型代码或合约类型名称都不能重复
     * 
     * @param channel 渠道标志
     * @param code 合约类型代码
     * @param name 合约类型名称
     * @param id 合约类型 id （新增合约类型时传空，更新时传入更新的合约类型 id）
     */
    private void checkRepeatContractType(String channel, String code, String name, Integer id) {
        LambdaQueryWrapper<ContractType> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractType::getChannel, channel);
        queryWrapper.eq(ContractType::getIsDeleted, SystemConsts.NOT_DELETED);
        queryWrapper.eq(ContractType::getCode, code);
        List<ContractType> list = this.list(queryWrapper);
        if (list != null && list.size() >= 1 && !list.get(0).getId().equals(id)) {
            throw new BusinessException("合约类型代码已存在", "ECCT0801");
        }
        queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractType::getChannel, channel);
        queryWrapper.eq(ContractType::getIsDeleted, SystemConsts.NOT_DELETED);
        queryWrapper.eq(ContractType::getName, name);
        list = this.list(queryWrapper);
        if (list != null && list.size() >= 1 && !list.get(0).getId().equals(id)) {
            throw new BusinessException("合约类型名称已存在", "ECCT0802");
        }
    }

    /**
     * 根据合约类型 id 校验是否是有效且允许操作
     * 
     * @param id 合约类型 id
     * @return 合约类型对象
     */
    public ContractType validContractType(Integer id, String channel) {
        ContractType contractType = this.getById(id);
        if (contractType == null || contractType.getIsDeleted()) {
            throw new BusinessException("无效的合约类型", "ECCT0800");
        }
        // 跨渠道访问交由内管控制 不由渠道端自行控制 by yangbh in 20200708 start
        /*if (!contractType.getChannel().equals(channel)) {
            throw new BusinessException("当前操作渠道与数据添加渠道不一致", "ECCT0003");
        }*/
        // 跨渠道访问交由内管控制 不由渠道端自行控制 by yangbh in 20200708 end
        return contractType;
    }

    /**
     * 检查合约类型是否被使用 <br />
     * 已被使用，会抛出异常
     * 
     * @param contractType 合约类型
     * @param req 基础请求对象
     */
    public void checkContractTypeIsUsed(ContractType contractType, BaseReqObj req) {
        // 查询模板有没有使用到该类型
        LambdaQueryWrapper<Template> templateQueryWrapper = new LambdaQueryWrapper<>();
        templateQueryWrapper.eq(Template::getIsDeleted, SystemConsts.NOT_DELETED);
        templateQueryWrapper.eq(Template::getChannel, req.getChannel());
        templateQueryWrapper.eq(Template::getContractTypeId, contractType.getId());
        int count = templateModel.count(templateQueryWrapper);
        if (count > 0) {
            throw new BusinessException("该合约类型已被使用", "ECCT0803");
        }
        // 查询合约是否使用该合约类型
        LambdaQueryWrapper<Contract> contractQueryWrapper = new LambdaQueryWrapper<>();
        contractQueryWrapper.eq(Contract::getChannel, req.getChannel());
        contractQueryWrapper.eq(Contract::getIsDeleted, SystemConsts.NOT_DELETED);
        contractQueryWrapper.eq(Contract::getContractTypeCode, contractType.getCode());
        count = templateModel.count(templateQueryWrapper);
        if (count > 0) {
            throw new BusinessException("该合约类型已被使用", "ECCT0803");
        }
    }

}
